package cn.promonkey.sso.controller;

import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;

import cn.promonkey.api.button.service.ButtonService;
import cn.promonkey.api.group.service.GroupService;
import cn.promonkey.api.log.entity.Log;
import cn.promonkey.api.log.service.LogService;
import cn.promonkey.api.menu.entity.Menu;
import cn.promonkey.api.menu.service.MenuService;
import cn.promonkey.api.menuInterface.service.InterfaceService;
import cn.promonkey.api.permission.entity.Permission;
import cn.promonkey.api.permission.service.PermissionService;
import cn.promonkey.api.relation.entity.Relation;
import cn.promonkey.api.relation.service.RelationService;
import cn.promonkey.api.user.entity.User;
import cn.promonkey.api.user.service.UserService;
import cn.promonkey.core.base.Constants;
import cn.promonkey.core.dto.UserDto;
import cn.promonkey.core.response.ResultMsg;
import cn.promonkey.core.toolkit.HttpClientUtils;
import cn.promonkey.sso.entity.CurrentRoutes;
import cn.promonkey.sso.entity.LoginUser;
import jakarta.servlet.http.HttpServletRequest;
import cn.promonkey.core.utils.MD5Utils;
import cn.promonkey.core.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;

/** @author <no value> */
@Slf4j
@RestController
@RequestMapping("/sso/")
public class SsoController {
	
	final RedisUtils redisUtils;
	
	final UserService userService;
	
	final GroupService groupService;
	
	final PermissionService permissionService;
	
	final RelationService relationService;
	
	final MenuService menuService;
	
	final InterfaceService interfaceService;
	
	final ButtonService buttonService;
	
	final LogService logService;
	
	@Value("${weixin.appId}")
    private String appId;
	
	@Value("${weixin.appSecret}")
    private String appSecret;

	public SsoController(UserService userService,RedisUtils redisUtils,GroupService groupService,PermissionService permissionService
			,RelationService relationService,MenuService menuService,InterfaceService interfaceService,ButtonService buttonService,LogService logService) {
		this.userService = userService;
		this.redisUtils = redisUtils;
		this.groupService = groupService;
		this.permissionService = permissionService;
		this.relationService = relationService;
		this.menuService = menuService;
		this.interfaceService = interfaceService;
		this.buttonService = buttonService;
		this.logService = logService;
	}
	
	@RequestMapping("v1/oauth2/mini_access_token")
	public String miniAccessToken(@RequestBody LoginUser loginUser,
		      HttpServletRequest request) {
		String code = loginUser.getCode();
		
		String rtnStr = HttpClientUtils.doGetRequest("https://api.weixin.qq.com/sns/jscode2session?appid="+appId+"&secret="+appSecret+"&js_code="+code+"&grant_type=authorization_code", null, null);

  		JSONObject rtnJSON = JSONObject.parseObject(rtnStr);
  		//系统繁忙时重试
  		while(rtnJSON!=null && null!=rtnJSON.getString("errcode") && "-1".equals(rtnJSON.getString("errcode"))) {
  			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
  			rtnStr = HttpClientUtils.doGetRequest("https://api.weixin.qq.com/sns/jscode2session?appid="+appId+"&secret="+appSecret+"&js_code="+code+"&grant_type=authorization_code", null, null);
  		}
  		//正常登录
  		if (rtnJSON!=null && null == rtnJSON.getString("errcode")) {
  			String openid = rtnJSON.getString("openid");
  			String session_key = rtnJSON.getString("session_key");
  			String unionid = rtnJSON.getString("unionid");
  			
  			QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
  			queryWrapper.eq("openid",openid);
  			User sysuser = userService.getOne(queryWrapper);

  			if(sysuser!=null && sysuser.getUserName()!=null) {
  				loginUser.setUsername(sysuser.getPhone());
  				loginUser.setUserName(sysuser.getUserName());
  				loginUser.setType(sysuser.getType());
 			}else {
 				loginUser.setUsername(openid);
  				loginUser.setUserName("微信用户");
  				loginUser.setType(0);
 			}
  			if(sysuser == null) {
  				// 新建
  				// 生成一个16位的随机数
  				Random random = new Random();
  				StringBuilder sBuilder = new StringBuilder(16);
  				sBuilder.append(random.nextInt(99999999)).append(random.nextInt(99999999));
  				int len = sBuilder.length();
  				if (len < 16) {
  					for (int i = 0; i < 16 - len; i++) {
  						sBuilder.append("0");
  					}
  				}
  				sysuser = new User();
  				// 生成最终的加密盐
  				String salt = sBuilder.toString();
  				sysuser.setSalt(salt);
  				sysuser.setBusinessId(1l);
  				sysuser.setOpenid(openid);
  				sysuser.setUnionid(unionid);
  				sysuser.setName("微信用户");
  				sysuser.setUserName("微信用户");
  				sysuser.setType(0);
  				userService.save(sysuser);
  				loginUser.setUsername(sysuser.getPhone());
  				loginUser.setUserName(sysuser.getUserName());
  				loginUser.setName(sysuser.getName());
  				loginUser.setType(sysuser.getType());
  				//小程序对应功能前台展示
  				Relation relation = new Relation();
  				relation.setGroupId(10l);
  				relation.setBusinessId(1l);
  				relation.setSystemId(8l);
  				relation.setUserId(sysuser.getUserId());
  				relationService.save(relation);
  				//该功能对应后台 问卷、预约
  				Relation relation1 = new Relation();
  				relation1.setGroupId(9l);
  				relation1.setBusinessId(6l);
  				relation1.setSystemId(7l);
  				relation1.setUserId(sysuser.getUserId());
  				relationService.save(relation1);
  				
  			}
  			String salt = sysuser.getSalt();
			SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			sysuser.setDatetime(new Date());
			Calendar ca=Calendar.getInstance();
			ca.setTime(new Date());
			String accessToken = MD5Utils.md5AndSha(sysuser.getUserId() + sdf.format(ca.getTime()) + salt);
			ca.add(Calendar.HOUR_OF_DAY, 3);
			String refreshToken = MD5Utils.md5AndSha(sysuser.getUserId() + sdf.format(ca.getTime()) + salt);
			//redis缓存
			redisUtils.hset(Constants.ACCESS_TOKEN_HASH, accessToken, sysuser.getUserId(), 30*24*60*60);
			redisUtils.hset(Constants.REFRESH_TOKEN_HASH, refreshToken, sysuser.getUserId(), 3*30*24*60*60);
			//redis缓存
			redisUtils.hset(Constants.BUSINESS_ID, sysuser.getUserId()+"",sysuser.getBusinessId());
			//授权token
			loginUser.setAccess_token(accessToken);
			//刷新token
			loginUser.setRefresh_token(refreshToken);
			//到期时间,1小时，刷新token3小时
			loginUser.setExpires_in(60*60);
			loginUser.setToken_type("1");

			loginUser.setUserId(sysuser.getUserId());
			sysuser.setDatetime(new Date());
			userService.updateById(sysuser);
			return ResultMsg.success(loginUser);
  			
  		} else {
  			return ResultMsg.fail(500, "系统错误，错误码"+rtnJSON.getInteger("errcode"));
  		}
		
		
	}
	
	@RequestMapping("v1/oauth2/access_token")
	public String accessToken(@RequestBody LoginUser loginUser,
		      HttpServletRequest request) {
		QueryWrapper<User> queryWrapper = new QueryWrapper<User>();
		String password = loginUser.getPassword();
		queryWrapper.or().eq("user_name", loginUser.getUsername()).isNotNull("business_id");
		queryWrapper.or().eq("email", loginUser.getUsername()).isNotNull("business_id");
		queryWrapper.or().eq("phone", loginUser.getUsername()).isNotNull("business_id");
		User sysuser = userService.getOne(queryWrapper);
		if(sysuser!=null) {
			String salt = sysuser.getSalt();
			String encrypPassword = MD5Utils.md5AndSha(password + salt);
			if(!sysuser.getPassword().equals(encrypPassword)) {
				return ResultMsg.fail(500, "用户名或密码错误");
			}
			String tempAccessToken = request.getHeader("Authorization");
			if(null!=tempAccessToken) {
				Object uid = redisUtils.hget(Constants.ACCESS_TOKEN_HASH, tempAccessToken);
				if(uid!=null) {
					User user = userService.getById( Long.valueOf(((Integer) uid).intValue()));
					sysuser.setOpenid(user.getOpenid());
					sysuser.setUnionid(user.getUnionid());
					QueryWrapper<Relation> relationWrapper = new QueryWrapper<>();
					relationWrapper.eq("user_id", Long.valueOf(((Integer) uid).intValue()));
					relationService.remove(relationWrapper);
					userService.removeById(Long.valueOf(((Integer) uid).intValue()));
				}
			}
			SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			Calendar ca=Calendar.getInstance();
			ca.setTime(new Date());
			String accessToken = MD5Utils.md5AndSha(sysuser.getUserId() + sdf.format(ca.getTime()) + salt);
			ca.add(Calendar.HOUR_OF_DAY, 3);
			String refreshToken = MD5Utils.md5AndSha(sysuser.getUserId() + sdf.format(ca.getTime()) + salt);
			//redis缓存
			redisUtils.hset(Constants.ACCESS_TOKEN_HASH, accessToken, sysuser.getUserId(), 30*24*60*60);
			redisUtils.hset(Constants.REFRESH_TOKEN_HASH, refreshToken, sysuser.getUserId(), 3*30*24*60*60);
			//redis缓存
			redisUtils.hset(Constants.BUSINESS_ID, sysuser.getUserId()+"",sysuser.getBusinessId());
			//授权token
			loginUser.setAccess_token(accessToken);
			//刷新token
			loginUser.setRefresh_token(refreshToken);
			//到期时间,1小时，刷新token3小时
			loginUser.setExpires_in(60*60);
			loginUser.setToken_type("1");
			loginUser.setUsername(sysuser.getPhone());
			loginUser.setUserName(sysuser.getUserName());
			loginUser.setType(sysuser.getType());
			loginUser.setUserId(sysuser.getUserId());
			sysuser.setDatetime(new Date());
			userService.updateById(sysuser);
			return ResultMsg.success(loginUser);
		}else {
			return ResultMsg.fail(500, "用户名或密码错误");
		}
	}
	
	@RequestMapping("v1/oauth2/check_token")
	public String checkToken(@RequestBody LoginUser loginUser) {
		Object accessToken = redisUtils.hget(Constants.ACCESS_TOKEN_HASH, loginUser.getAccess_token());
		Object refreshToken = null;
		if(loginUser.getRefresh_token()!=null) {
			refreshToken = redisUtils.hget(Constants.REFRESH_TOKEN_HASH, loginUser.getRefresh_token());
		}
		UserDto dto = new UserDto();
		if(accessToken!=null) {
			redisUtils.hset(Constants.ACCESS_TOKEN_HASH, loginUser.getAccess_token(), accessToken, 30*24*60*60);
			if(refreshToken!=null) {
				redisUtils.hset(Constants.REFRESH_TOKEN_HASH, loginUser.getRefresh_token(), refreshToken, 3*30*24*60*60);
			}
			dto.setUserId(Long.parseLong(accessToken.toString()));
			Object businessId = redisUtils.hget(Constants.BUSINESS_ID, ""+accessToken);
			dto.setBusinessId(Long.valueOf((Integer)businessId));
    		Log log = new Log();
    		log.setBusinessId((Integer)businessId);
    		log.setUserId((Integer)accessToken);
    		log.setSendTime(loginUser.getSendTime());
    		log.setJson(loginUser.getJson());
    		log.setInterfaceKey(loginUser.getInterfaceKey());
    		//log.setMenuId(null);
    		log.setSystemId(loginUser.getSystemId());
    		logService.save(log);
		}else if(refreshToken!=null) {
				
		}
		return ResultMsg.success(dto);
	}
	
	@RequestMapping("v1/oauth2/refresh_token")
	public String refreshToken(@RequestBody LoginUser loginUser) {
		//Object accessToken = redisUtils.hget(Constants.ACCESS_TOKEN_HASH, loginUser.getAccess_token());
		Object userId = redisUtils.hget(Constants.REFRESH_TOKEN_HASH, loginUser.getRefresh_token());
		if(userId!=null) {
			//User sysuser = userService.getById((long) userId);
			//经过缓存后变成int型
			User sysuser = userService.getById(Long.valueOf((int) userId));
			String salt = sysuser.getSalt();
			SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			Calendar ca=Calendar.getInstance();
			ca.setTime(new Date());
			String accessToken = MD5Utils.md5AndSha(sysuser.getUserId() + sdf.format(ca.getTime()) + salt);
			ca.add(Calendar.HOUR_OF_DAY, 3);
			String refreshToken = MD5Utils.md5AndSha(sysuser.getUserId() + sdf.format(ca.getTime()) + salt);
			//redis缓存
			redisUtils.hset(Constants.ACCESS_TOKEN_HASH, accessToken, sysuser.getUserId(), 30*24*60*60);
			redisUtils.hset(Constants.REFRESH_TOKEN_HASH, refreshToken, sysuser.getUserId(), 3*30*24*60*60);
			//授权token
			loginUser.setAccess_token(accessToken);
			//刷新token
			loginUser.setRefresh_token(refreshToken);
			//到期时间,1小时，刷新token3小时
			loginUser.setExpires_in(60*60);
			loginUser.setToken_type("1");
			loginUser.setUsername(sysuser.getPhone());
			loginUser.setUserName(sysuser.getUserName());
			loginUser.setType(sysuser.getType());
			loginUser.setUserId(sysuser.getUserId());
			
		}else {
			return ResultMsg.fail("更新失败");
		}
		return ResultMsg.success(loginUser);
	}
	
	@RequestMapping("v1/external/user/user_info")
	public String userInfo(HttpServletRequest request) {
		String accessToken = request.getHeader("Authorization");
    	Object uid = redisUtils.hget(Constants.ACCESS_TOKEN_HASH, accessToken);
		//Object refreshToken = redisUtils.hget(Constants.REFRESH_TOKEN_HASH, loginUser.getRefresh_token());
		if(uid!=null) {
			User user = userService.getById((int)uid+0l);
			LoginUser loginUser = new LoginUser();
			loginUser.setUsername(user.getUserName());
			return ResultMsg.success(loginUser);
		}else {
			return ResultMsg.fail(401, "登录超时");
		}
	}
	
	@RequestMapping("v1/external/dev_menu/getCurrentRoutes")
	public String getCurrentRoutes(HttpServletRequest request) {
		String accessToken = request.getHeader("Authorization");
		String systemId = request.getHeader("SystemID");
    	Object uid = redisUtils.hget(Constants.ACCESS_TOKEN_HASH, accessToken);
		//Object refreshToken = redisUtils.hget(Constants.REFRESH_TOKEN_HASH, loginUser.getRefresh_token());
    	User user = null;
		if(uid!=null) {
			user = userService.getById((int)uid+0l);
		}else {
			return ResultMsg.fail(401, "登录超时");
		}
		CurrentRoutes currentRoutes = new CurrentRoutes();
		List<String> routerName = new ArrayList<>();
		List<String> allowInterface = new ArrayList<>();
		List<String> authWord = new ArrayList<>();
		
		//获取菜单和请求授权
		//获取关系数据
		QueryWrapper<Relation> relationWrapper = new QueryWrapper<Relation>();
		relationWrapper.eq("business_id", user.getBusinessId());
		relationWrapper.eq("system_id", Integer.valueOf(systemId));
		relationWrapper.eq("user_id", user.getUserId());
		List<Relation> relationList = relationService.list(relationWrapper);
		//获取所在权限组
		List<Long> groupList = relationList.stream().map(Relation::getGroupId).collect(Collectors.toList());
		//获取权限数据
		QueryWrapper<Permission> permissionWrapper = new QueryWrapper<Permission>();
		if(groupList.size()==0) {
			permissionWrapper.eq("group_id", 0);
		}else {
			permissionWrapper.in("group_id", groupList);
		}
		
		List<Permission> permissionList = permissionService.list(permissionWrapper);
		
		for(Permission permission:permissionList) {
			
			if(permission.getMenuId()!=0) {
				
				Menu menu = menuService.getById(permission.getMenuId());
				
				if(null!=menu) {
					routerName.add(menu.getMenuKey());
				}
			}
			if(permission.getInterfaceId()!=0) {
				allowInterface.add(interfaceService.getById(permission.getInterfaceId()).getInterfaceKey());
			}
			if(permission.getButtonId()!=0) {
				authWord.add(buttonService.getById(permission.getButtonId()).getButtonKey());
			}
			
		}
		
		currentRoutes.setRouterNames(routerName);
		currentRoutes.setAllowInterfaces(allowInterface);
		currentRoutes.setAuthWords(authWord);
		return ResultMsg.success(currentRoutes);
	}

}
